-- The variable containing the current menu item selection is reset
-- to its initial level. The variable "blocs" contains the top and
-- bottom locations for each menu item button, one pair to a line.
-- The side coordinates are not needed because they are all the same
-- and are given by the side coordinates of the menu field
global b,blocs
put 0 into b
get rect of btn 1
put item 2 of it into blocs
put item 4 of it into item 2 of blocs
get rect of btn 2
put item 2 of it into line 2 of blocs
put item 4 of it into item 2 of line 2 of blocs
get rect of btn 3
put item 2 of it into line 3 of blocs
put item 4 of it into item 2 of line 3 of blocs
get rect of btn 4
put item 2 of it into line 4 of blocs
put item 4 of it into item 2 of line 4 of blocs
end openCard
on mouseDown
-- Sets the "ok" variable to true if the initial mouseDown occurs
-- somewhere inside the simulated menubar, so the mouseStillDown
-- handler will activate the menu if the cursor is subsequently
-- dragged over the "apple" menu title.
global ok
put the mouseH into mH
put the mouseV into mV
if mH > 111 and mH < 393 and mV > 95 and mV < 114 then
put true into ok
else
put false into ok
end if
end mouseDown
on mouseStillDown
-- Handles most of the actions of the menubar. Remember, once the
-- mouse button is pressed this is the only message being sent by the
-- HyperCard system, so checking the mouse position (i.e. is the
-- cursor over a given button) cannot be gotten from mouseWithin or
-- similar messages, but must be checked against the rectangle of
-- the object being watched for. This handler had to be placed above
-- the "apple" title button level so the mouseStillDown messages sent
-- from the card level if the button is first depressed within the
-- menubar but not over the actual "apple" title button would reach
-- then same mouseStillDown handler and cause the menu to activate if
-- the cursor is subsequently dragged over the "apple" title button.
global b,blocs,ok
-- First, if "ok" is true (the initial mouseDown occurred either over
-- the "apple" menu title or somewhere else inside the menubar),
-- allow the menu actions to take place.
if ok then
put the mouseV into mV -- Get the cursor location.
put the mouseH into mH
-- Check to see if the cursor has been dragged over the "apple" menu
-- title. First, is the cursor above the bottom of the menubar?
if mV < 113 then
-- If so, is the cursor within the bounds of the "apple" menu?
if mH < 121 or mH > 149 or mV < 97 then
send mouseUp to btn 5 -- If it is over the "apple" menu, then
else -- send the "apple" button a mouseDown
send mouseDown to btn 5 -- (show the menu) otherwise send it a
end if -- mouseUp (hide the menu).
repeat with n = 1 to 4 -- Then un-hilite the menu item buttons.
set hilite of btn n to false
end repeat
exit mouseStillDown -- And leave this message handler (no
end if -- other actions will be necessary).
-- If the cursor is below the menubar, is it somewhere over the
-- menu field itself, and if so, over which button (which must be
-- hilited)?
if mV ≥ 113 and mV ≤ 178 and mH ≥ 121 and mH ≤ 231 then
put b into oldB -- A place holder for the last button hilited.
-- The following loop checks to find which menu item the cursor is
-- over, and hilites the button over it so it appears to be
-- selected. The variable "b" contains the number of the currently
-- hilited button, and the search begins from the next higher ID
-- button (the next one lower on the menu) so that when the menu
-- is dragged _down_ (the most common direction to drag along a
-- menu) the first button checked is the one immediately below the
-- last button hilited, which improves the menu reaction just a
-- bit when dragging the mouse _down_ the menu. The variable
-- "blocs" contains the top and bottom coordinates for each menu
-- item button, one pair to a line.
repeat 4 times
add 1 to b
if b > 4 then put 1 into b -- Only four buttons are in the menu
if mV ‚â• item 1 of line b of blocs and mV < item 2 of line b of blocs then
-- Once it is known which button the cursor is currently over
-- that button is hilited, and the last menu item button
-- hilited is un-hilited (if it is not the same as the new
-- button, or it would blink on and off, and it is not 0,
-- which is the reset number and not a button that can be
-- unhilited).
set hilite of btn b to true
if oldB ≠ 0 and oldB ≠ b then set hilite of btn oldB to false
exit mouseStillDown -- Leave this handler, no more actions
end if -- necessary.
end repeat
else
-- If the cursor is not over the menu while it is showing, then
-- un-hilite all of the buttons and reset the currently selected
-- button to 0.
repeat with n = 1 to 4
set hilite of btn n to false
end repeat
put 0 into b
end if
end if
end mouseStillDown
on idle
-- For a menu selection to take place the mouse button must be
-- released over one of the hilited menu item buttons. Consequently
-- there will be no mouseUp message sent to the object that was
-- receiving the mouseStillDown messages (either the "apple" menu
-- title button, or the card itself if the button is initially
-- depressed within the menubar but not over the "apple" menu button).
-- So the only way to have the menu react after the mouse button is
-- released is to operate on the idle message which is then being
-- sent.
global b
-- First, so the computer doesn't get tied up executing many
-- HyperTalk commands while idle messages are being sent (which is
-- all the time the mouse button is not depressed), the first thing
-- this checks is whether the menu field itself is visible. If the
-- field is not visible no menu items can have been selected, so
-- the handler is quickly bypassed.
if the visible of card field 1 then
-- If variable "b" is not reset to 0 then a menu item has been
-- selected, so the normal menu actions are executed.
if b ≠ 0 then
repeat 3 times -- The menu item selected is
set hilite of btn b to false -- flashed three times.
set hilite of btn b to true
end repeat
set hilite of btn b to false
hide card field 1 -- The menu field is hidden, and the "apple"
set hilite of btn 5 to false -- menu title button is un-hilited
-- The number of the button over which the mouse button was
-- released was set up so that it corresponded to the line number
-- of the item selected in the menu field. To make the menu look
-- better, two spaces were placed before each menu item, which
-- must are removed before the doMenu command completes the menu
-- action
get line b of card field 1
delete char 1 to 2 of it
doMenu it
repeat with n = 1 to 4 -- Finally, when execution speed is no
hide btn n -- longer a problem, the menu item buttons
end repeat -- are hidden.
else
-- If variable "b" is 0 while the menu is showing, and the mouse
-- button is then released, it means the cursor is not somewhere
-- over the menu, so the menu and the item buttons are hidden
-- and the "apple" menu button is un-hilited.
hide card field 1
set hilite of btn 5 to false
repeat with n = 1 to 4
hide btn n
end repeat
end if
end if
end idle
-- part 6 (field)
-- low flags: 80
-- high flags: 0004
-- rect: left=121 top=113 right=181 bottom=234
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: Fake Menu Field
-- part 1 (button)
-- low flags: 80
-- high flags: 0000
-- rect: left=122 top=114 right=130 bottom=231
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: New Button
-- part 2 (button)
-- low flags: 80
-- high flags: 0000
-- rect: left=122 top=130 right=146 bottom=231
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: New Button
-- part 3 (button)
-- low flags: 80
-- high flags: 0000
-- rect: left=122 top=146 right=162 bottom=231
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: New Button
-- part 4 (button)
-- low flags: 80
-- high flags: 0000
-- rect: left=122 top=162 right=178 bottom=231
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name:
-- part 5 (button)
-- low flags: 00
-- high flags: 8000
-- rect: left=121 top=97 right=113 bottom=149
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name:
----- HyperTalk script -----
on mouseUp -- The menu field is hidden, the "apple"
global b -- menu title is un-hilited, the buttons
hide card field 1 -- that sit over the menu items are hidden,
set hilite of me to false -- and the variable containing the current
repeat with n = 1 to 4 -- menu item selection (b) is reset.
hide btn n
end repeat
put 0 into b
end mouseUp
on mouseDown -- The "apple" menu title is hilited, the
global b,ok -- menu field is shown, the buttons that sit
set hilite of me to true -- over the menu items are shown, the
show card field 1 -- variable containing the current menu item
repeat with n = 1 to 4 -- selection (b) is reset, and the variable
show button id n -- (ok) that tells the mouseStillDown handler
end repeat -- whether or not to allow a drag over the
put 0 into b -- menu title to activate the menu is set.
put true into ok
end mouseDown
-- The mouseStillDown handler is placed at the card level, because there
-- is another mouseDown handler at the card level (that sets the "ok"
-- variable to true if the initial mouseDown is inside the menubar but
-- not over the "apple" menu title) which uses the same mouseStillDown
-- handler. The mouseStillDown handler does most of the tasks that make
-- the menubar function.
-- part 8 (button)
-- low flags: 00
-- high flags: 2000
-- rect: left=362 top=215 right=235 bottom=383
-- title width / last selected line: 0
-- icon id / first selected line: 19678 / 19678
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: About This Stack
----- HyperTalk script -----
on mouseUp
set scroll of card field 2 to 0
hide btn 7
hide btn id 14
hide btn id 18
hide btn id 20
show card field 2
end mouseUp
-- part 9 (field)
-- low flags: 81
-- high flags: 0007
-- rect: left=12 top=56 right=299 bottom=497
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 4
-- text size: 9
-- style flags: 0
-- line height: 12
-- part name: About field
----- HyperTalk script -----
on mouseUp
hide card field 2
show btn 7
show btn id 14
show btn id 18
show btn id 20
end mouseUp
-- part 10 (field)
-- low flags: 80
-- high flags: 0007
-- rect: left=21 top=33 right=285 bottom=491
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 4
-- text size: 9
-- style flags: 0
-- line height: 12
-- part name: Temp Script Holder
-- part 11 (button)
-- low flags: 00
-- high flags: A003
-- rect: left=185 top=272 right=294 bottom=316
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: Show Menu Parts
----- HyperTalk script -----
on mouseUp
if card field 3 is empty then
put the script of this card into card field 3
put the script of btn id 5 into card field 4
set script of this card to empty
set script of btn id 5 to empty
show card field 1
repeat with n = 1 to 4
show btn n
end repeat
set name of me to "Hide Menu Parts"
show card field 5
set userLevel to 5
choose button tool
show tool window
set loc of tool window to 18,111
else
set the script of this card to card field 3
set the script of btn id 5 to card field 4
put empty into card field 3
put empty into card field 4
hide card field 5
repeat with n = 1 to 4
hide btn n
end repeat
hide card field 1
set name of me to "Show Menu Parts"
if the hilite of btn "do browsing" then set userLevel to 1
end if
end mouseUp
-- part 12 (field)
-- low flags: 80
-- high flags: 0007
-- rect: left=30 top=60 right=159 bottom=474
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 4
-- text size: 9
-- style flags: 0
-- line height: 12
-- part name: Temp Script Holder
-- part 13 (field)
-- low flags: 81
-- high flags: 2002
-- rect: left=151 top=33 right=75 bottom=345
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: Warning (danger, Will Robinson!)
-- part 14 (button)
-- low flags: 00
-- high flags: A003
-- rect: left=160 top=305 right=327 bottom=346
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: Remove Script Comments
----- HyperTalk script -----
on mouseUp
hide msg
if the optionKey is down then
if the short name of me is "remove script comments" then
answer "This will reset scripts for comment removal." with "OK" or "Cancel"
if it is not "cancel" then
put empty into card field id 15
put empty into card field id 16
put empty into card field id 17
end if
end if
else
put false into done
if the short name of me is "remove script comments" then
if card field id 15 is empty and card field id 16 is empty and card field id 17 is empty then
answer "Comments may be restored later" with "Cancel" or "OK"
if it is "Cancel" then
exit mouseUp
else
set loc of msg to 17,140
set cursor to 4
repeat with x = 1 to 3
if x = 1 then
put the script of this stack into scriptHolder
put "the stack script" into theName
end if
if x = 2 then
put the script of this card into scriptHolder
put "the card script" into theName
end if
if x = 3 then
put the script of btn id 5 into scriptHolder
put "the" && quote & "apple" & quote && "button script" into theName
end if
put the number of lines in scriptHolder into theLines
put 1 into n
repeat until n = theLines
put "Removing comments from line" && n && "out of" && theLines && "of" && theName
put the number of chars in line n of scriptHolder into theChars
put offset("-",line n of scriptHolder) into start
if start ≠ 0 then
put false into exiit
repeat until exiit
if char start-1 of line n of scriptHolder is " " then
subtract one from start
else
put true into exiit
end if
end repeat
delete char start to theChars of line n of scriptHolder
repeat until exiit
if first char of line n of scriptHolder is " " then
delete first char of line n of scriptHolder
else
put true into exiit
end if
end repeat
end if
if line n of scriptHolder is empty then
delete line n of scriptHolder
else
add 1 to n
end if
put the number of lines in scriptHolder into theLines
end repeat
if x = 1 then put scriptHolder into stackHolder
if x = 2 then put scriptHolder into cardHolder
if x = 3 then put scriptHolder into btnHolder
end repeat
put " Finished!"
wait 1 seconds
hide msg
put true into done
end if
end if
set the name of me to "Restore Script Comments"
hide btn id 19
else
set the name of me to "Remove Script Comments"
show btn id 19
end if
set cursor to 4
if not done then
put card field id 15 into stackHolder
put card field id 16 into cardHolder
put card field id 17 into btnHolder
end if
put the script of this stack into card field id 15
put the script of this card into card field id 16
put the script of btn id 5 into card field id 17
set the script of this stack to stackHolder
set the script of this card to cardHolder
set the script of btn id 5 to btnHolder
end if
end mouseUp
-- part 15 (field)
-- low flags: 80
-- high flags: 0002
-- rect: left=152 top=46 right=58 bottom=164
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 4
-- text size: 9
-- style flags: 0
-- line height: 12
-- part name: Stack Script
-- part 16 (field)
-- low flags: 80
-- high flags: 0002
-- rect: left=247 top=46 right=58 bottom=259
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 4
-- text size: 9
-- style flags: 0
-- line height: 12
-- part name: Card Script
-- part 17 (field)
-- low flags: 80
-- high flags: 0002
-- rect: left=346 top=45 right=57 bottom=358
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 0
-- font id: 4
-- text size: 9
-- style flags: 0
-- line height: 12
-- part name: Button Script
-- part 18 (button)
-- low flags: 00
-- high flags: C006
-- rect: left=397 top=277 right=299 bottom=502
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: Do Scripting
----- HyperTalk script -----
on mouseUp
set hilite of me to true
set hilite of btn "do browsing" to false
set userLevel to 5
end mouseUp
-- part 20 (button)
-- low flags: 00
-- high flags: 8006
-- rect: left=397 top=308 right=330 bottom=502
-- title width / last selected line: 0
-- icon id / first selected line: 0 / 0
-- text alignment: 1
-- font id: 0
-- text size: 12
-- style flags: 0
-- line height: 16
-- part name: Do Browsing
----- HyperTalk script -----
on mouseUp
set hilite of me to true
set hilite of btn "do scripting" to false
set userLevel to 1
end mouseUp
-- part contents for card part 6
----- text -----
Alarm Clock
Control Panel
Key Caps
Scrapbook
-- part contents for card part 9
----- text -----
*********************************************
* *
* Menu Emulation *
* by William G. Anderson, Jr. *
* April 1988 *
* *
* CIS id 76254,356 *
* *
*********************************************
This stack is an exercise to simulate the actions of the menubar using nothing but HyperTalk. Granted the objects involved do not react as quickly as those of a real menubar, but if you pass over the menu items slowly enough they will do a passable imitation of a real menubar. This was written on a Mac+ with a Radius accelerator board, so on non-accelerated Macs it may be very slow (I have no way to know). A hard disk also speeds things up considerably.
Special notes: 1. The scripts of this stack, which are located at the stack
level, the card level, and in the "apple" button (which
is the title of the simulated menubar), are all heavily
commented for your convenience. I can't be sure, but this
does seem to slow the action of the simulated menu slighty.
It also obscures the structure of the scripts. Therefore,
I have included a button to strip the comments from the
scripts of this stack. The actual removal of comments only
happens the first time the button is used, at which time
both the commented and uncommented versions of the scripts
are stored. Future use of the button merely places the
stored version into the script, and the script version
goes into storage. So you can quickly toggle between the
two versions as needed. (If you wish to remove the
comments again and watch the numbers sail by, hold down
the option key while clicking on the "remove script
comments" button. This will reset the scripts and fields
so the next mouse up will remove the comments again, while
considerably shrinking the size of this stack.)
2. The locations and numbers of the buttons and field used by
the scripts are fixed whithin the scripts themselves. If
you move, remove, or change the size of any of these
objects the simulation will fail unless you change the
scripts to accomodate the changes you make.
3. There is an idle message handler that removes the menu
field and its buttons from the screen when they are
visible. Also, the "apple" menu button itself will
similarly hide the menu field and buttons. To make it
possible for you to examine the menu and its buttons, the
"Show Menu Parts" button temporarily stores the "apple"
menu button script and card level scripts in hidden fields,
sets the user level to "scripting," shows the tool window
and chooses the button tool (to show the menu item buttons
over the menu field). When you are finished examining the
menu field and its buttons, clicking on the "Hide Menu
Parts" button will restore the card and button scripts,
resetting the menu emulation.
Actions performed by the simulated menu:
(Any mention below of terms such as "menu" or "menubar" refer to the simulated menubar in the center of the screen, not the real one. Also, all references to "dragging" the mouse mean a continuous mouse down from the time the mouse was first clicked over some area that would normally actuate the menu.)
1. A mouseDown on the "apple" menu title causes the menu title to hilite,
and the menu to show.
2. Dragging the mouse over the items of the menu causes them to hilite when
the mouse is over them, and un-hilite when the mouse is no longer over
them.
3. Dragging the mouse completely off the menu itself (to either side or the
bottom) causes all menu items to be un-selected.
4. Dragging the mouse back over the menu while still below the menubar
causes the menu item first dragged over to hilite.
5. Releasing the mouse button while over a hilited menu item causes the menu
item to blink on and off three times, the menu disappears from the screen,
the menu title un-hilites, and the selected action occurs.
6. Releasing the mouse button while the menu is showing but no menu items
are hilited (i.e. the mouse is below the menubar but is to one side of or
below the menu) causes the menu to disappear and the menu title to un-
hilite.
7. If the cursor is no longer over the menu title when the cursor is dragged
above the bottom of the menubar the menu disappears and the menu title
will un-hilite.
8. After the occurance of item 7 above, dragging the mouse over the menu
title causes the menu title to hilite and the menu will reappear.
9. If the mouseDown initially occurs somewhere inside the menubar, but not
over the menu title itself, dragging the cursor over the menu title will
cause the menu title to hilite and the menu will appear.
10. Dragging the cursor _down_ the menu will cause the menu items passed
over to hilite and un-hilite faster than when dragging _up_ the menu. It
was simple to optimize the script for one direction or the other, and
since menus are initially scanned down I selected that direction to have
the better reaction time.
Note: While writing this I found that having any graphics in the card layer
substantially slowed the speed at which the HyperTalk scripts used in
this stack ran. Perhaps it is not a good idea to put graphics in the
card layer at all, if it can be avoided.
-- part contents for card part 13
----- text -----
Click on button "Hide Menu Parts" to re-enable menu